class Fn {
    constructor() {
      this.keys = this.getAllKeys()
      this.frozen = false
      this.appendix = '_expire'
      this.used = localStorage ? JSON.stringify(localStorage).length : 0
      this.clearExpiredCache()
    }
    getType(obj) {
      return Object.prototype.toString
        .call(obj)
        .match(/\s[^\]]+/g)[0]
        .replace(/^\s/g, '')
        .toLowerCase()
    }
    /**
     * 设置缓存.
     * @param {string} key - key.
     * @param {string} value - value.
     * @param {number} secs - 有效期，单位为秒，默认为0，表示永久缓存
     */
    set(key, value, secs = 0) {
      if (+secs !== 0 && !/^[1-9]\d*$/.test(secs)) {
        secs = 86400
      }
      // 缓存只允许存数组、对象、数字、字符串
      let valueType = this.getType(value)
      let permissionTypes = ['array', 'object', 'number', 'string'];
      // 验证key是否为字符串
      if (this.getType(key) !== 'string') {
        return {
          code: 'ERR_INVALID_KEY',
          msg: '无效的缓存key'
        }
      }
      // 验证vlaue的类型是否为permissionTypes中所指定的
      if (permissionTypes.indexOf(valueType) === -1) {
        return {
          code: 'ERR_INVALID_VALUE',
          msg: '无效的缓存值'
        }
      }
      // 每次设置时，清除当前缓存
      this.remove(key)
      if (['array','object'].indexOf(valueType) > -1) {
        value = JSON.stringify(value)
      }
      let expireKey = key + this.appendix
      let expireMilliSecs = new Date().getTime() + secs * 1000
  /*     if (this.frozen) {
        return {
          code: 'ERR_MAXIMUM_CAPACITY',
          msg: '达到最大存储容量'
        }
      } */
      try {
        localStorage.setItem(key, value)
        // secs这个描述大于0时，设置的缓存会带有有效期，有效期为设置的秒数
        if (+secs > 0) {
          localStorage.setItem(expireKey, expireMilliSecs)
        }
        this.used = localStorage ? JSON.stringify(localStorage).length : 0
        if (this.keys.indexOf(key) === -1) {
          this.keys.push(key)
        }
      } catch (e) {
      /*   this.frozen = true
        return {
          code: 'ERR_MAXIMUM_CAPACITY',
          msg: '达到最大存储容量'
        } */
        // 当缓存达到最大容量时，清空缓存
        this.removeAll()
      }
      // 正常设置缓存，则返回null
      return null
    }
    /**
     * 读取指定key缓存.
     * @param {string} key - key.
     * @param {string} type - 可取值array、object、string、number（传入对应参数，返回标准类型）.
     */
    get(key, type = 'string') {
      if (this.getType(key) !== 'string') {
        return
      }
      let expireKey = key + this.appendix
      if (
        localStorage.getItem(expireKey) &&
        new Date().getTime() > localStorage.getItem(expireKey)
      ) {
        localStorage.removeItem(key)
        localStorage.removeItem(expireKey)
        return null
      }
      let storageStr = localStorage.getItem(key)
      if (type === 'number') {
        return isNaN(+storageStr) ? null : +storageStr
      }
      if (type === 'object') {
        try {
          let parseObj = JSON.parse(storageStr)
          if (this.getType(parseObj) === 'object') {
            return parseObj
          }
          return {}
        } catch (e) {
          return null
        }
      }
      if (type === 'array') {
        try {
          let parseObj = JSON.parse(storageStr)
          if (Array.isArray(parseObj)) {
            return parseObj
          }
          return []
        } catch (e) {
          return null
        }
      }
      return localStorage.getItem(key)
    }
    /**
     * 删除指定key缓存.
     * @param {string} key - key.
     */
    remove(key) {
      let expireKey = key + this.appendix
      localStorage.removeItem(key)
      localStorage.removeItem(expireKey)
      this.used = localStorage ? JSON.stringify(localStorage).length : 0
    }
    /**
     * 获取所有缓存的key.
     */
    getAllKeys() {
      let keys = []
      for (let x in localStorage) {
        let hasKey = localStorage.hasOwnProperty(x)
        let reg = /_expire$/
        if (hasKey && !reg.test(x)) {
          keys.push(x)
        }
      }
      return keys
    }
    /**
     * 清除所有过期的缓存.
     */
    clearExpiredCache() {
      let allKeys = this.keys
      if (!allKeys.length) {
        return
      }
      allKeys.forEach((key) => {
        let expireKey = key + this.appendix
        if (
          localStorage.getItem(expireKey) &&
          new Date().getTime() > localStorage.getItem(expireKey)
        ) {
          localStorage.removeItem(key)
          localStorage.removeItem(expireKey)
          this.keys = this.keys.filter((item) => item !== key)
        }
      })
      this.used = localStorage ? JSON.stringify(localStorage).length : 0
    }
    /**
     * 移除所有缓存.
     * @param {array} excludeKeys - excludeKeys包含的key将不会被移除.
     */
    removeAll(excludeKeys = []) {
      let keys = []
      excludeKeys.forEach((item) => {
        excludeKeys.push(item + this.appendix)
      })
      for (let key in localStorage) {
        if (excludeKeys.indexOf(key) > -1) {
          let reg = /_expire$/
          if (!reg.test(key)) {
            keys.push(key)
          }
        } else {
          this.remove(key)
        }
      }
      this.keys = keys
      this.used = localStorage ? JSON.stringify(localStorage).length : 0
      // 全部清除缓存后，重置frozen为false，此时又可以开始写缓存
      this.frozen = false
    }

     //缓存数据，如果存入的是对象或数组，取出则还原，其他取出是什么就是什么，有对应的过期时间，过期时间不传不能设置
     setWithExpire(key = '', value, expireTimeStamp = 0) {
      if (!key) {
        return console.error(`设置storage的key-${key}为空，请检查`)
      }
      //不用校验数据类型
      if (!expireTimeStamp || typeof expireTimeStamp !== 'number') {
        return console.error(
          `设置storage的key-${key}的过期时间或类型错误，请检查`
        )
      }

      //如果是对象或数组
      if (
        Array.isArray(value) ||
        Object.prototype.toString.call(value).includes('Object')
      ) {
        this.set(key, JSON.stringify(value))
      } else {
        this.set(key, value)
      }

      //自动生成对应的key，按规则生成
      let expireKey = `${key}_a_d_expire`

      //同时设置一个过期时间
      this.set(expireKey, expireTimeStamp)
    }
    //取出缓存的数据，如果是对象或数组，则还原成对象或数组，其他类型直接返回，如果过期了，直接返回null
    getWithExpire(key = '') {
      if (!key) {
        return console.error(`获取的storage的key-${key}为空，请检查`)
      }

      //自动生成对应的key，按规则生成
      let expireKey = `${key}_a_d_expire`

      //先校验过期时间
      let expireTime = this.get(expireKey)
      //没有对应的缓存过期时间或已经过期了，则直接返回null
      if (!expireTime) return null

      //已经过期了，则清除对应的key和expireKeythis.get(
      if (+expireTime <= Date.now()) {
        this.remove(key)
        this.remove(expireKey)
        return null
      }

      //如果是对象或数组，则还原成对象或数组
      let cache = this.get(key)

      if (!cache) return null

      try {
        //不管有没有，能不能解析，直接解析，出错就返回null
        cache = JSON.parse(this.get(key))
      } catch (e) {}

      return cache
    }
  }
  function init() {
    window.storage = new Fn()
  }
  export default { init }